package com.suxin.lock;

import org.springframework.data.redis.core.StringRedisTemplate;

import java.time.Clock;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * @author Tang
 * @classname DistributedCountDownLatch
 * @description [基于redis的分布式countDownLatch]
 * @date 2021/3/12 22:51
 */
public class DistributedCountDownLatch {

    final int count;
    private String lockName;
    private static StringRedisTemplate redisTemplate;
    
    public DistributedCountDownLatch(int count) {
        this.count = count;
    }

    public DistributedCountDownLatch(int count,String lockName) {
        this(count);
        this.lockName = lockName;
    }

    /**
     * 必须全局初始化一次
     * @param redisTemplate
     */
    private static void init(StringRedisTemplate redisTemplate) {
        DistributedCountDownLatch.redisTemplate = redisTemplate;
    }

    private void clear() {
        redisTemplate.delete(lockName);
    }

    public void countDown() {
        redisTemplate.opsForValue()
                .increment(lockName, -1);
    }

    /**
     * 阻塞等待
     */
    public void await() {
        // 循环阻塞
        while (getCount()) {
            try {
                TimeUnit.MILLISECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        clear();
    }

    /**
     * 超时等待
     * @param time
     * @param timeUnit
     * @return 是否是超时结束
     */
    public boolean await(Long time, TimeUnit timeUnit) {
        boolean isTimeOut = false;
        long startTime = Clock.systemDefaultZone().millis();
        while (getCount()) {
            if (Clock.systemDefaultZone().millis() - startTime > timeUnit.toMillis(time)) {
                countDown();
                isTimeOut = true;
                break;
            }
        }
        return isTimeOut;
    }

    private boolean getCount() {
        String value = Optional.ofNullable(redisTemplate.opsForValue().get(lockName)).orElse("0");
        return Integer.parseInt(value) > 0;
    }

}